
cmspad.ajax = {

	nls:{
		COMM_ERROR: 'Communication Error',
		USER_ABORT: 'User Terminated'
	},
	
	post: function(uri, callback, data){
		return this._send('POST', uri, callback, data);
	},
	
	get: function(uri, callback){
		return this._send('GET', uri, callback);
	},
	
	_ACTIVEX: ['MSXML2.XMLHTTP.5.0', 'MSXML2.XMLHTTP.4.0', 'MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP', 'Microsoft.XMLHTTP'],
	
	/**
	 * 存储XMLHTTPReqeust对象的ID序列.
	 */
	_xhrId: 1,
	
	/**
	 * 存储已创建的XMLHttpRequest对象池.
	 */
	_xhrPool: {},
	
	/**
	 * _xhrPool的轮询检查时间间隔
	 */
	_xhrInterval: 50,
	
	/**
	 * 存储已设置的XMLHttpRequest对象池.
	 */
	_xhrTimeout: {},
	
	/**
	 * 创建XMLHttpRequest对象
	 *
	 * @param string Transcation ID
	 * @return XMLHttpRequest
	 */
	_conn: function(tid){
		var obj, xhr;
		try {
			xhr = new XMLHttpRequest();
			obj = {
				xhr: xhr,
				tid: tid
			};
		} catch (e) {
			for (var i = 0, l = this._ACTIVEX.length; i < l; ++i) {
				try {
					xhr = new ActiveXObject(this._ACTIVEX[i]);
					obj = {
						xhr: xhr,
						tid: tid
					};
					break;
				} catch (e) {
					continue;
				}
			}
			
			if (!xhr && window.createRequest) {
				xhr = window.createRequest();
				obj = {
					xhr: xhr,
					tid: tid
				};
			}
		} finally {
			return obj;
		}
	},
	
	/**
	 * 初始化XMLHttpRequest对象.
	 */
	_init: function(){
		var o;
		var tid = this._xhrId;
		try {
			o = this._conn(tid);
			if (o) {
				this._xhrId++;
			}
		} finally {
			return o;
		}
	},
	
	/**
	 *
	 * <ul> callback 对象的可选属性和方法：
	 * <li>onready(): 发送请求前调用该函数。</li>
	 * <li>success(o): 成功收到回应时调用该函数。</li>
	 * <li>failure(o,a): 无法收到回应时调用该函数。</li>
	 * <li>timeout: 当前请求超时时间。</li>
	 * <li>headers: 自定义的HTTP头</li>
	 * <li>argument: 自定义的参数，用于识别对象。</li>
	 * </ul>
	 *
	 * @param {Object} method 提交类型：GET、POST
	 * @param {Object} uri 提交的URI路径
	 * @param {Object} callback 回调对象
	 * @param {Object} postdata POST请求数据
	 */
	_send: function(method, uri, callback, postdata){
		var o = this._init();
		if (o) {
		
			if (callback && callback.onready) {
				callback.onready();
			}
			
			// 打开请求连接
			o.xhr.open(method, uri, true);
			
			// 添加HTTP头
			if (postdata) {
				o.xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
			}
			o.xhr.setRequestHeader('Referer', self.location.href);
			
			// 自定义HTTP头
			if (callback && callback.headers) {
				for (var k in callback.headers) {
					if (typeof k == 'string') {
						v = callback.headers[k];
						o.xhr.setRequestHeader(k, v);
					}
				}
			}
			
			// 设置回调函数
			this._event(o, callback);
			
			// 发送POST数据
			o.xhr.send(postdata || null);
			
			return o.xhr;
		} else {
			return null;
		}
	},
	
	_event: function(o, callback){
		var ajax = this;
		
		// 如果回调对象设置了超时时限，则先使用它的
		if (callback && callback.timeout) {
			this._xhrTimeout[o.tid] = window.setTimeout(function(){
				ajax._abort(o, callback, true);
			}, callback.timeout);
		}
		
		// 否则，则使用系统默认的超时检查
		this._xhrPool[o.tid] = window.setInterval(function(){
			if (o.xhr && o.xhr.readyState == 4) {
				window.clearInterval(ajax._xhrPool[o.tid]);
				delete ajax._xhrPool[o.tid];
				
				if (callback && callback.timeout) {
					window.clearTimeout(ajax._xhrTimeout[o.tid]);
					delete ajax._xhrTimeout[o.tid];
				}
				
				ajax._trans(o, callback);
			}
		}, this._xhrInterval);
	},
	
	_trans: function(o, callback, isAbort){
		if (!callback) {
			this._free(o);
			return;
		}
		
		var httpStatus, responseObject;
		
		try {
			if (o.xhr.status !== undefined && o.xhr.status != 0) {
				httpStatus = o.xhr.status;
			} else {
				httpStatus = 13030;
			}
		} catch (e) {
			httpStatus = 13030;
		}
		
		if (httpStatus >= 200 && httpStatus < 300) {
			responseObject = this._crobj(o, callback.argument);
			if (callback.success) {
				callback.success(responseObject);
			}
		} else {
			switch (httpStatus) {
				case 12002:
				case 12029:
				case 12030:
				case 12031:
				case 12152:
				case 13030:
					responseObject = this._ceobj(o.tid, callback.argument, (isAbort ? isAbort : false));
					if (callback.failure) {
						callback.failure(responseObject);
					}
					break;
				default:
					responseObject = this._crobj(o, callback.argument);
					if (callback.failure) {
						callback.failure(responseObject);
					}
			}
		}
		
		this._free(o);
		responseObject = null;
	},
	
	_free: function(o){
		o.xhr = null;
		o = null;
	},
	
	_crobj: function(o, callbackArg){
		var obj = {};
		var headers = {};
		
		try {
			var header = o.xhr.getAllResponseHeaders().split('\n');
			for (var i = 0; i < header.length; i++) {
				var delimitPos = header[i].indexOf(':');
				if (delimitPos != -1) {
					headers[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
				}
			}
		} catch (e) {
		}
		
		obj.tid = o.tid;
		obj.status = o.xhr.status;
		obj.statusText = o.xhr.statusText;
		obj.header = headers;
		obj.responseText = o.xhr.responseText;
		obj.responseXML = o.xhr.responseXML;
		
		if (typeof callbackArg !== undefined) {
			obj.argument = callbackArg;
		}
		
		return obj;
	},
	
	_ceobj: function(tid, callbackArg, isAbort){
		var COMM_CODE = 0;
		var COMM_ERROR = cmspad.ajax.nls.COMM_ERROR; // NLS: ajax.COMM_ERROR
		var ABORT_CODE = -1;
		var USER_ABORT = cmspad.ajax.nls.USER_ABORT; // NLS: ajax.USER_ABORT
		var obj = {};
		obj.tid = tid;
		if (isAbort) {
			obj.status = ABORT_CODE;
			obj.statusText = USER_ABORT;
		} else {
			obj.status = COMM_CODE;
			obj.statusText = COMM_ERROR;
		}
		
		if (callbackArg) {
			obj.argument = callbackArg;
		}
		
		return obj;
	},
	
	_abort: function(o, callback, isTimeout){
		if (this._using(o)) {
			o.xhr.abort();
			window.clearInterval(this._xhrPool[o.tid]);
			delete this._xhrPool[o.tid];
			if (isTimeout) {
				delete this._xhrTimeout[o.tid];
			}
			this._trans(o, callback, true);
			return true;
		} else {
			return false;
		}
	},
	
	_using: function(o){
		if (o.xhr) {
			return o.xhr.readyState != 4 && o.xhr.readyState != 0;
		} else {
			return false;
		}
	}
};